import gradio as gr
import pandas as pd
import numpy as np
import plotly.graph_objects as go


target_text_ini = f"2023年，统计局公布的农村人均低保标准城市为622元，城市为786元每月，现行贫困标准为3218元每年"\
                f"，折合268元每月，农村人均可支配收入为1927元每月，按照替代率50%计算，可支配收入为964元每月"


def plot_both_target(add_target_value):
    return plot_target(add_target_value), plot_tree(add_target_value)

def plot_target(add_target_value):
    categories_target = ['23年城乡居民养老月均', '现行贫困标准', '农村人均低保标准', '城市人均低保标准', '农村人均可支配收入', '建议标准']
    values_target = [222, 268, 622, 786, 1927, add_target_value]
    texts = [f"{s}元" for s in values_target]
    # 为每个柱子设置颜色，将建议标准的柱子颜色设为红色
    colors = ['black','blue', 'blue', 'blue', 'blue', 'red']
    
    # 创建柱状图，设置柱子颜色
    fig = go.Figure(data=[go.Bar(x=categories_target, y=values_target, text=texts ,marker_color=colors)])
    
    # 添加一条红色虚线，高度等于 888
    fig.add_shape(
        type="line",
        x0=-0.5,
        y0=add_target_value,
        x1=len(categories_target) - 0.5,
        y1=add_target_value,
        line=dict(color="red", dash="dash")
    )
    
    # 设置图表标题和坐标轴标签
    fig.update_layout(title='2023年相关收入标准', xaxis_title='收入标准类别', yaxis_title='金额：元/月')
    return fig

def plot_tree(add_target_value):
    # 数据准备
    categories = ['政策目标','城乡居民基本养老', '企业职工基本养老', '机关单位退休金']
    values = [add_target_value, 223, 3300, 6200]
    texts = [f"{s}元" for s in values]
    # widths = [0.549, 0.397, 0.054]
    widths = [1, 1, 0.694, 0.127]
    # 设置柱子颜色，政策目标为红色，其他为蓝色
    colors = ['red'] + ['blue'] * (len(categories) - 1)
    # 创建柱状图
    fig = go.Figure(data=[go.Bar(
        x=categories,
        y=values,
        width=widths,  # 设置每个柱子的宽度
        text=texts,
        textposition='outside',
        textfont={'size': 20},
        marker_color=colors  # 设置柱子颜色
    )])
    # 绘制高度为 777 的水平线
    fig.add_shape(
        type="line",
        x0=-0.5,
        y0=add_target_value,
        x1=len(categories) - 0.5,
        y1=add_target_value,
        line=dict(color="black", dash="dash")  # 可根据需要调整线条颜色和样式
    )
    # 更新布局，设置柱子之间的间隙为 0
    fig.update_layout(
        barmode='group',  # 设置柱状图模式
        bargap=1,         # 设置柱子之间的间隙为 0
        title='2023年不同群体月均基本养老金及建议目标，宽度代表人群占比',
    )
    return fig

class ShowAnalysis:
    def __init__(self):
        self.monthly_inflow = 223
        self.amount_of_people = 18268 * 10000
        self.data = pd.DataFrame()
    
    def yearly_people(self, choice, assets, roe, ratio_of_dividend_payment,increment_of_people, 
                      total_dividend, inter_year, mph, fill_gap, target_monthly_amount):
        year = 2025
        amount_of_people = self.amount_of_people
        
        df = pd.DataFrame(index=list(range(20)))
        df['year'] = df.index
        df['year'] = df['year'].apply(lambda x: x + year)
        df['领取人数(人)'] = [amount_of_people + i * increment_of_people * 10000 for i in range(20)]
        
        print('choice', choice, 'assets', assets, 'roe', roe, 'ratio_of_dividend_payment', ratio_of_dividend_payment,
              'increment_of_people', increment_of_people, 'total_dividend', total_dividend, 'inter_year', inter_year,
              'mph', mph, 'fill_gap', fill_gap, 'target_monthly_amount', target_monthly_amount)
        
        if choice == "划拨分红":
            yearly_flow = assets * roe * ratio_of_dividend_payment
        else:
            yearly_flow = assets
        
        flow_from_capital = []
        cum_assets = 0
        for i in range(20):
            year += 1
            if i >= inter_year:
                flow_from_capital.append(cum_assets)
            else:
                cum_assets += yearly_flow
                flow_from_capital.append(cum_assets)
                
        df['累计划拨资本'] = flow_from_capital
        df['每年国有资本收益:万亿'] = df['累计划拨资本'] * roe * ratio_of_dividend_payment
        df['资本收益折合人均养老金/年'] = 10000 * 10000 * 10000 * df['每年国有资本收益:万亿'] / df['领取人数(人)']
        df['资本收益折合人均养老金/月'] = df['资本收益折合人均养老金/年'] / 12

        df['按照月均目标应发养老金/月'] = target_monthly_amount
        df['按照月均目标应发养老金/年'] = df['按照月均目标应发养老金/月'] * 12

        df['是否由财政补贴缺口'] = fill_gap
        df['人均缺口/月'] = df['按照月均目标应发养老金/月'] - df['资本收益折合人均养老金/月'] - 222
        df['人均缺口/年'] = df['人均缺口/月'] * 12

        if fill_gap:
            df['财政补贴'] = df['人均缺口/年'] * df['领取人数(人)'] / (10000 * 10000 * 10000)
            df['计划养老基金/月'] = df['按照月均目标应发养老金/月']
        else:
            df['财政补贴'] = 0
            df['计划养老基金/月'] = df['资本收益折合人均养老金/月'] + 223
        
        df['增量资金:万亿（资本收益+财政补贴）'] = (df['计划养老基金/月'] - 223) * 12 * df['领取人数(人)'] / (10000 * 10000 * 10000)
        df['拉动消费（万亿）'] = df['增量资金:万亿（资本收益+财政补贴）'] * mph

        df = df.applymap(lambda x: '{:.2f}'.format(x) if isinstance(x, float) else x)
        df.index = [f"{s}年" for s in pd.Series(df['year'])]
        self.data = df
        df_t = df.T
        df_t.insert(0, '指标', df_t.index)
        radio_cols = [s for s in df.columns.to_list() if s!= 'year']
        return df_t, gr.Radio(radio_cols, label="选择列", value=radio_cols[-1])
    
    def plot_se(self, col):
        se = self.data[col]
        # 确保 se 是 pandas.Series 或 pandas.DataFrame 对象
        if isinstance(se, (pd.Series, pd.DataFrame)):
            x = se.index.to_list()
            # 原代码
            y = se.to_list() if isinstance(se, pd.Series) else se.values.flatten().tolist()
            # 将 y 中的元素转换为浮点型
            y = [float(i) for i in y]
        else:
            # 处理 se 不是 pandas 对象的情况
            print("se 不是 pandas.Series 或 pandas.DataFrame 对象")
            return None

        hov = [f'{c}年:{v}' for c, v in zip(x, y)]
        # 为每个柱子添加标签
        text_labels = [str(v) for v in y]
        # 创建柱状图，添加 text 和 textposition 参数
        fig = go.Figure(data=[go.Bar(x=x, y=y, hovertext=hov, text=text_labels, textposition='outside')])
        # 设置图表标题和坐标轴标签
        fig.update_layout(title=f"{se.name}",xaxis_title='年')
        return fig
    
    def cal_cum_money(self, choice, assets, inter_year, roe, ratio_of_dividend_payment):
        if choice == "划拨分红":
            return self.cal_money_from_dividend(assets, inter_year, roe, ratio_of_dividend_payment)
        elif choice == "划拨资本":
            return self.cal_money_from_assets(assets, inter_year, roe, ratio_of_dividend_payment)

    def cal_money_from_dividend(self, assets, inter_year, roe, ratio_of_dividend_payment):
        total_dividend = assets * roe * ratio_of_dividend_payment # 每年分红
        total_assets = 0
        for i in range(inter_year):
            total_assets += total_assets * roe # 累计的财富
            total_assets += total_dividend # 每年分红
        div = total_assets * roe
        ff = f"每年利用分红再投资，不影响国有资本股权结构，\n累计的财富（资产配置）为【{total_assets:.2f}】万亿元，\n这些财富按照资本回报=roe可形成每年现金流【{div:.2f}】万亿元"
        return total_assets, div, ff

    def cal_money_from_assets(self, assets, inter_year, roe, ratio_of_dividend_payment):
        total_assets = assets * inter_year 
        total_dividend = total_assets * roe * ratio_of_dividend_payment
        ff = f"每年划拨净资产，\n累计的财富（国有资本）为【{total_assets:.2f}】万亿元，\n这些资本按照roe可形成每年现金流【{total_dividend:.2f}】万亿元"
        return total_assets, total_dividend, ff
    
    def save_excel(self, df, save_path):
        try:
            df.to_excel(save_path, index=False)
            gr.Info(f"数据已成功保存到 {save_path}")
        except Exception as e:
            gr.Error(f"保存数据时出错: {str(e)}")
        print(f"数据已保存到 {save_path}")
        
    def html(self):
        with gr.Blocks() as demo:
            gr.Markdown("# 社保模拟分析,从国有资本补充社保基金测算")
            gr.Markdown("[数据来源:2023人力资源和社会保障事业发展统计公报](https://www.mohrss.gov.cn/SYrlzyhshbzb/zwgk/szrs/tjgb/202406/W020240617617024381518.pdf)")
            gr.Markdown("## 步骤一：筹集资金测算")
            with gr.Row():
                choice = gr.Radio(["划拨分红", "划拨资本"], label="筹资的是资产还是分红", value="划拨资本",interactive=True,scale=1)
                assets = gr.Slider(0, 80, 1, step=0.1, label="划拨国有资本净资产(万亿元)", interactive=True,scale=2)
            with gr.Row():
                inter_year = gr.Slider(1, 15, 10, step=1, label="筹集资金年数", interactive=True)
                roe = gr.Slider(0.005, 0.1, 0.066, step=0.001, label="ROE(净资产收益率0.5-8%)", interactive=True)
                ratio_of_dividend_payment = gr.Slider(0, 1, 0.7, step=0.01, label="分红比例0-100%", interactive=True)
            #
            gr.Markdown("## 输出结果")
            with gr.Row():
                total_assets = gr.Number(label="累计的财富(万亿元)", value=0, interactive=False, scale=1) 
                total_dividend = gr.Number(label="每年现金流(万亿元)", value=0, interactive=False,scale=1)
                ff = gr.Textbox(label="筹资过程：", value="", interactive=False,scale=2)
            
            gr.on(triggers=[choice.change, assets.change, inter_year.change, roe.change, ratio_of_dividend_payment.change],
                  fn=self.cal_cum_money,
                  inputs=[choice, assets, inter_year, roe, ratio_of_dividend_payment],
                  outputs=[total_assets, total_dividend, ff])
            gr.Markdown("## 步骤二：设定政策目标，城乡居民养老金涨到多少？")
            with gr.Row():
                target_slider = gr.Slider(244, 1000, 564, step=1, label="城乡居民养老金涨到多少元/月", interactive=True, scale=3)
                set_target_bt = gr.Button("设定目标", scale=1)
            # target_text = gr.Textbox(label="目标：", value=target_text_ini, interactive=False, lines=3)
            with gr.Row():
                with gr.Tab("目标设定"):
                    target_fig = gr.Plot()
                with gr.Tab("政策目标"):
                    three = gr.Plot()
            gr.Markdown("## 步骤三：每年资金流平均分配给城乡居民养老金人口")
            
            with gr.Row():
                increment_of_people = gr.Slider(0, 1000, 600, step=5, label="每年增加的领取人(万)", interactive=True,scale=3)
                fill_gap = gr.Checkbox(label="是否需要增量财政资金补充缺口", value=True, interactive=True)
                cal_bt = gr.Button(scale=1)
            
            with gr.Tab("测算详情"):
                cols_check = gr.Radio(label="选择列", choices=[], interactive=True, scale=2)
                mph_slider = gr.Slider(0, 1, 0.8, step=0.01, label="边际消费倾向", interactive=True, scale=1)
                plot_a_col = gr.Plot()

            with gr.Tab("数据表"):
                with gr.Row():
                    save_path = gr.Textbox(label="保存路径", value="D:\\", interactive=True)
                    bt_save_excel = gr.Button("保存数据到Excel")
                tt = gr.DataFrame(label="每年资金流平均分配给城乡居民养老金人口：")
            
            cols_check.change(fn=self.plot_se, inputs=[cols_check], outputs=[plot_a_col])
            
            bt_save_excel.click(self.save_excel, inputs=[tt, save_path], outputs=[])
            
            set_target_bt.click(fn=plot_both_target,
                                 inputs=[target_slider],
                                 outputs=[target_fig, three])
            target_slider.change(fn=plot_both_target,
                                 inputs=[target_slider],
                                 outputs=[target_fig, three])
            
            gr.on(triggers=[increment_of_people.change, cal_bt.click],
                  fn=self.yearly_people,
                  inputs=[choice, assets, roe, ratio_of_dividend_payment,increment_of_people, 
                          total_dividend, inter_year, mph_slider, fill_gap, target_slider],
                  outputs=[tt , cols_check])
        return demo
    
sd = ShowAnalysis()
sd.html().launch()
# sd.html().launch(share=True, server_name='0.0.0.0')